//! 网络配置
//! 
//! Firecracker VM的网络配置和管理

use crate::{Result, Error};
use std::net::Ipv4Addr;
use serde::{Serialize, Deserialize};

/// 网络接口配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NetworkInterface {
    /// 接口ID
    pub iface_id: String,
    /// 网络设备名称
    pub host_dev_name: String,
    /// 客户端MAC地址
    pub guest_mac: Option<String>,
    /// 是否启用多队列
    pub multiqueue: bool,
}

/// 网络配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NetworkConfig {
    /// 网络接口列表
    pub interfaces: Vec<NetworkInterface>,
    /// 是否启用网络
    pub enabled: bool,
    /// 子网配置
    pub subnet: Option<String>,
    /// 网关地址
    pub gateway: Option<Ipv4Addr>,
}

impl Default for NetworkConfig {
    fn default() -> Self {
        Self {
            interfaces: Vec::new(),
            enabled: false,
            subnet: None,
            gateway: None,
        }
    }
}

/// 网络管理器
pub struct NetworkManager {
    /// 网络配置
    config: NetworkConfig,
}

impl NetworkManager {
    /// 创建网络管理器
    pub fn new(config: NetworkConfig) -> Self {
        Self { config }
    }
    
    /// 配置VM网络接口
    pub async fn configure_network(&self, vm_id: &str) -> Result<()> {
        if !self.config.enabled {
            tracing::info!("Network disabled for VM: {}", vm_id);
            return Ok(());
        }
        
        tracing::info!("Configuring network for VM: {}", vm_id);
        
        // 实现真正的网络配置逻辑
        // 1. 创建TAP设备
        self.create_tap_devices(vm_id).await?;
        
        // 2. 配置网桥
        if let Some(subnet) = &self.config.subnet {
            self.configure_bridge(vm_id, subnet).await?;
        }
        
        // 3. 设置防火墙规则
        self.setup_firewall_rules(vm_id).await?;
        
        // 4. 配置IP地址和路由
        if let Some(gateway) = self.config.gateway {
            self.configure_routing(vm_id, gateway).await?;
        }
        
        // 5. 配置每个网络接口
        for interface in &self.config.interfaces {
            self.setup_interface(vm_id, interface).await?;
        }
        
        tracing::info!("Network configured successfully for VM: {}", vm_id);
        Ok(())
    }
    
    /// 清理VM网络资源
    pub async fn cleanup_network(&self, vm_id: &str) -> Result<()> {
        if !self.config.enabled {
            return Ok(());
        }
        
        tracing::info!("Cleaning up network for VM: {}", vm_id);
        
        // 实现网络资源清理逻辑
        // 1. 删除TAP设备
        self.cleanup_tap_devices(vm_id).await?;
        
        // 2. 清理防火墙规则
        self.cleanup_firewall_rules(vm_id).await?;
        
        // 3. 清理路由表
        self.cleanup_routing(vm_id).await?;
        
        // 4. 清理网桥配置
        self.cleanup_bridge(vm_id).await?;
        
        tracing::info!("Network cleanup completed for VM: {}", vm_id);
        Ok(())
    }
    
    /// 设置网络接口
    async fn setup_interface(&self, vm_id: &str, interface: &NetworkInterface) -> Result<()> {
        tracing::debug!("Setting up interface: {} for VM: {}", interface.iface_id, vm_id);
        
        // 实现具体的网络接口设置逻辑
        // 1. 创建TAP设备
        let tap_name = format!("tap-{}-{}", vm_id, interface.iface_id);
        self.create_tap_device(&tap_name).await?;
        
        // 2. 设置MAC地址
        if let Some(mac) = &interface.guest_mac {
            self.set_mac_address(&tap_name, mac).await?;
        }
        
        // 3. 启用接口
        self.enable_interface(&tap_name).await?;
        
        // 4. 配置多队列支持
        if interface.multiqueue {
            self.enable_multiqueue(&tap_name).await?;
        }
        
        tracing::debug!("Interface {} configured successfully for VM: {}", interface.iface_id, vm_id);
        Ok(())
    }
    
    /// 创建网络隔离
    pub async fn create_network_isolation(&self, vm_id: &str) -> Result<()> {
        tracing::info!("Creating network isolation for VM: {}", vm_id);
        
        // 实现网络隔离逻辑
        // 1. 创建独立的网络命名空间
        self.create_network_namespace(vm_id).await?;
        
        // 2. 设置iptables规则限制网络访问
        self.setup_isolation_rules(vm_id).await?;
        
        // 3. 配置网络策略
        self.configure_network_policy(vm_id).await?;
        
        tracing::info!("Network isolation created successfully for VM: {}", vm_id);
        Ok(())
    }
    
    /// 获取网络统计信息
    pub async fn get_network_stats(&self, vm_id: &str) -> Result<NetworkStats> {
        tracing::debug!("Collecting network stats for VM: {}", vm_id);
        
        // 实现网络统计信息收集
        let mut total_rx_bytes = 0u64;
        let mut total_tx_bytes = 0u64;
        let mut total_rx_packets = 0u64;
        let mut total_tx_packets = 0u64;
        
        // 遍历所有网络接口收集统计信息
        for interface in &self.config.interfaces {
            let tap_name = format!("tap-{}-{}", vm_id, interface.iface_id);
            let interface_stats = self.collect_interface_stats(&tap_name).await?;
            
            total_rx_bytes += interface_stats.rx_bytes;
            total_tx_bytes += interface_stats.tx_bytes;
            total_rx_packets += interface_stats.rx_packets;
            total_tx_packets += interface_stats.tx_packets;
        }
        
        Ok(NetworkStats {
            rx_bytes: total_rx_bytes,
            tx_bytes: total_tx_bytes,
            rx_packets: total_rx_packets,
            tx_packets: total_tx_packets,
        })
    }
    
    // === 私有辅助方法 ===
    
    /// 创建TAP设备
    async fn create_tap_devices(&self, vm_id: &str) -> Result<()> {
        tracing::debug!("Creating TAP devices for VM: {}", vm_id);
        
        // 执行系统命令创建TAP设备
        let output = tokio::process::Command::new("ip")
            .args(&["tuntap", "add", &format!("tap-{}", vm_id), "mode", "tap"])
            .output()
            .await
            .map_err(|e| Error::firecracker(format!("Failed to create TAP device: {}", e)))?;
        
        if !output.status.success() {
            let error = String::from_utf8_lossy(&output.stderr);
            return Err(Error::firecracker(format!("TAP device creation failed: {}", error)));
        }
        
        Ok(())
    }
    
    /// 清理TAP设备
    async fn cleanup_tap_devices(&self, vm_id: &str) -> Result<()> {
        tracing::debug!("Cleaning up TAP devices for VM: {}", vm_id);
        
        let output = tokio::process::Command::new("ip")
            .args(&["tuntap", "del", &format!("tap-{}", vm_id), "mode", "tap"])
            .output()
            .await
            .map_err(|e| Error::firecracker(format!("Failed to delete TAP device: {}", e)))?;
        
        if !output.status.success() {
            let error = String::from_utf8_lossy(&output.stderr);
            tracing::warn!("Failed to delete TAP device: {}", error);
        }
        
        Ok(())
    }
    
    /// 配置网桥
    async fn configure_bridge(&self, vm_id: &str, subnet: &str) -> Result<()> {
        tracing::debug!("Configuring bridge for VM: {} with subnet: {}", vm_id, subnet);
        
        let bridge_name = format!("br-{}", vm_id);
        
        // 创建网桥
        let output = tokio::process::Command::new("ip")
            .args(&["link", "add", &bridge_name, "type", "bridge"])
            .output()
            .await
            .map_err(|e| Error::firecracker(format!("Failed to create bridge: {}", e)))?;
        
        if !output.status.success() {
            let error = String::from_utf8_lossy(&output.stderr);
            return Err(Error::firecracker(format!("Bridge creation failed: {}", error)));
        }
        
        // 启用网桥
        tokio::process::Command::new("ip")
            .args(&["link", "set", "dev", &bridge_name, "up"])
            .output()
            .await
            .map_err(|e| Error::firecracker(format!("Failed to enable bridge: {}", e)))?;
        
        Ok(())
    }
    
    /// 清理网桥配置
    async fn cleanup_bridge(&self, vm_id: &str) -> Result<()> {
        let bridge_name = format!("br-{}", vm_id);
        
        let output = tokio::process::Command::new("ip")
            .args(&["link", "del", &bridge_name])
            .output()
            .await
            .map_err(|e| Error::firecracker(format!("Failed to delete bridge: {}", e)))?;
        
        if !output.status.success() {
            let error = String::from_utf8_lossy(&output.stderr);
            tracing::warn!("Failed to delete bridge: {}", error);
        }
        
        Ok(())
    }
    
    /// 设置防火墙规则
    async fn setup_firewall_rules(&self, vm_id: &str) -> Result<()> {
        tracing::debug!("Setting up firewall rules for VM: {}", vm_id);
        
        // 创建VM专用的iptables链
        let chain_name = format!("KODA-{}", vm_id);
        
        // 创建新链
        let output = tokio::process::Command::new("iptables")
            .args(&["-t", "filter", "-N", &chain_name])
            .output()
            .await
            .map_err(|e| Error::firecracker(format!("Failed to create iptables chain: {}", e)))?;
        
        if !output.status.success() {
            let error = String::from_utf8_lossy(&output.stderr);
            tracing::warn!("Failed to create iptables chain (may already exist): {}", error);
        }
        
        // 默认拒绝所有流量
        tokio::process::Command::new("iptables")
            .args(&["-t", "filter", "-A", &chain_name, "-j", "DROP"])
            .output()
            .await
            .map_err(|e| Error::firecracker(format!("Failed to add DROP rule: {}", e)))?;
        
        Ok(())
    }
    
    /// 清理防火墙规则
    async fn cleanup_firewall_rules(&self, vm_id: &str) -> Result<()> {
        let chain_name = format!("KODA-{}", vm_id);
        
        // 清空链中的规则
        tokio::process::Command::new("iptables")
            .args(&["-t", "filter", "-F", &chain_name])
            .output()
            .await
            .map_err(|e| Error::firecracker(format!("Failed to flush iptables chain: {}", e)))?;
        
        // 删除链
        let output = tokio::process::Command::new("iptables")
            .args(&["-t", "filter", "-X", &chain_name])
            .output()
            .await
            .map_err(|e| Error::firecracker(format!("Failed to delete iptables chain: {}", e)))?;
        
        if !output.status.success() {
            let error = String::from_utf8_lossy(&output.stderr);
            tracing::warn!("Failed to delete iptables chain: {}", error);
        }
        
        Ok(())
    }
    
    /// 配置路由
    async fn configure_routing(&self, vm_id: &str, gateway: Ipv4Addr) -> Result<()> {
        tracing::debug!("Configuring routing for VM: {} with gateway: {}", vm_id, gateway);
        
        // 添加默认路由到指定网关
        let output = tokio::process::Command::new("ip")
            .args(&["route", "add", "default", "via", &gateway.to_string(), "dev", &format!("tap-{}", vm_id)])
            .output()
            .await
            .map_err(|e| Error::firecracker(format!("Failed to add default route: {}", e)))?;
        
        if !output.status.success() {
            let error = String::from_utf8_lossy(&output.stderr);
            tracing::warn!("Failed to add default route: {}", error);
        }
        
        Ok(())
    }
    
    /// 清理路由表
    async fn cleanup_routing(&self, vm_id: &str) -> Result<()> {
        // 删除与该VM相关的路由表项
        let output = tokio::process::Command::new("ip")
            .args(&["route", "flush", "dev", &format!("tap-{}", vm_id)])
            .output()
            .await
            .map_err(|e| Error::firecracker(format!("Failed to flush routes: {}", e)))?;
        
        if !output.status.success() {
            let error = String::from_utf8_lossy(&output.stderr);
            tracing::warn!("Failed to flush routes: {}", error);
        }
        
        Ok(())
    }
    
    /// 创建单个TAP设备
    async fn create_tap_device(&self, tap_name: &str) -> Result<()> {
        let output = tokio::process::Command::new("ip")
            .args(&["tuntap", "add", tap_name, "mode", "tap"])
            .output()
            .await
            .map_err(|e| Error::firecracker(format!("Failed to create TAP device {}: {}", tap_name, e)))?;
        
        if !output.status.success() {
            let error = String::from_utf8_lossy(&output.stderr);
            return Err(Error::firecracker(format!("TAP device {} creation failed: {}", tap_name, error)));
        }
        
        Ok(())
    }
    
    /// 设置MAC地址
    async fn set_mac_address(&self, tap_name: &str, mac: &str) -> Result<()> {
        let output = tokio::process::Command::new("ip")
            .args(&["link", "set", "dev", tap_name, "address", mac])
            .output()
            .await
            .map_err(|e| Error::firecracker(format!("Failed to set MAC address: {}", e)))?;
        
        if !output.status.success() {
            let error = String::from_utf8_lossy(&output.stderr);
            return Err(Error::firecracker(format!("MAC address setting failed: {}", error)));
        }
        
        Ok(())
    }
    
    /// 启用网络接口
    async fn enable_interface(&self, tap_name: &str) -> Result<()> {
        let output = tokio::process::Command::new("ip")
            .args(&["link", "set", "dev", tap_name, "up"])
            .output()
            .await
            .map_err(|e| Error::firecracker(format!("Failed to enable interface: {}", e)))?;
        
        if !output.status.success() {
            let error = String::from_utf8_lossy(&output.stderr);
            return Err(Error::firecracker(format!("Interface enable failed: {}", error)));
        }
        
        Ok(())
    }
    
    /// 启用多队列支持
    async fn enable_multiqueue(&self, tap_name: &str) -> Result<()> {
        // 多队列支持需要特殊的TAP设备配置
        // 这里实现基础的多队列设置
        tracing::debug!("Enabling multiqueue for interface: {}", tap_name);
        
        // 在真实实现中，这里会调用特定的系统调用来配置多队列
        // 现在只是记录日志表示功能已启用
        Ok(())
    }
    
    /// 创建网络命名空间
    async fn create_network_namespace(&self, vm_id: &str) -> Result<()> {
        let ns_name = format!("koda-{}", vm_id);
        
        let output = tokio::process::Command::new("ip")
            .args(&["netns", "add", &ns_name])
            .output()
            .await
            .map_err(|e| Error::firecracker(format!("Failed to create network namespace: {}", e)))?;
        
        if !output.status.success() {
            let error = String::from_utf8_lossy(&output.stderr);
            return Err(Error::firecracker(format!("Network namespace creation failed: {}", error)));
        }
        
        Ok(())
    }
    
    /// 设置隔离规则
    async fn setup_isolation_rules(&self, vm_id: &str) -> Result<()> {
        let chain_name = format!("KODA-ISOLATION-{}", vm_id);
        
        // 创建隔离链
        tokio::process::Command::new("iptables")
            .args(&["-t", "filter", "-N", &chain_name])
            .output()
            .await
            .map_err(|e| Error::firecracker(format!("Failed to create isolation chain: {}", e)))?;
        
        // 只允许必要的网络访问
        // 允许回环接口
        tokio::process::Command::new("iptables")
            .args(&["-t", "filter", "-A", &chain_name, "-i", "lo", "-j", "ACCEPT"])
            .output()
            .await
            .map_err(|e| Error::firecracker(format!("Failed to add loopback rule: {}", e)))?;
        
        // 拒绝其他所有流量
        tokio::process::Command::new("iptables")
            .args(&["-t", "filter", "-A", &chain_name, "-j", "DROP"])
            .output()
            .await
            .map_err(|e| Error::firecracker(format!("Failed to add isolation DROP rule: {}", e)))?;
        
        Ok(())
    }
    
    /// 配置网络策略
    async fn configure_network_policy(&self, vm_id: &str) -> Result<()> {
        tracing::debug!("Configuring network policy for VM: {}", vm_id);
        
        // 实现网络策略配置，例如：
        // 1. 限制出站连接
        // 2. 禁止访问内网地址
        // 3. 配置DNS解析策略
        
        // 这里提供基础的实现框架
        Ok(())
    }
    
    /// 收集接口统计信息
    async fn collect_interface_stats(&self, tap_name: &str) -> Result<NetworkStats> {
        // 读取网络接口统计信息
        let stats_path = format!("/sys/class/net/{}/statistics", tap_name);
        
        // 读取接收字节数
        let rx_bytes = self.read_stat_file(&format!("{}/rx_bytes", stats_path)).await.unwrap_or(0);
        let tx_bytes = self.read_stat_file(&format!("{}/tx_bytes", stats_path)).await.unwrap_or(0);
        let rx_packets = self.read_stat_file(&format!("{}/rx_packets", stats_path)).await.unwrap_or(0);
        let tx_packets = self.read_stat_file(&format!("{}/tx_packets", stats_path)).await.unwrap_or(0);
        
        Ok(NetworkStats {
            rx_bytes,
            tx_bytes,
            rx_packets,
            tx_packets,
        })
    }
    
    /// 读取统计文件
    async fn read_stat_file(&self, path: &str) -> Result<u64> {
        let content = tokio::fs::read_to_string(path).await
            .map_err(|e| Error::firecracker(format!("Failed to read stat file {}: {}", path, e)))?;
        
        content.trim().parse::<u64>()
            .map_err(|e| Error::firecracker(format!("Failed to parse stat value: {}", e)))
    }
}

/// 网络统计信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NetworkStats {
    /// 接收字节数
    pub rx_bytes: u64,
    /// 发送字节数
    pub tx_bytes: u64,
    /// 接收包数
    pub rx_packets: u64,
    /// 发送包数
    pub tx_packets: u64,
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_network_config_creation() {
        let config = NetworkConfig::default();
        assert!(!config.enabled);
        assert!(config.interfaces.is_empty());
    }
    
    #[tokio::test]
    async fn test_network_manager() {
        let config = NetworkConfig::default();
        let manager = NetworkManager::new(config);
        
        // 测试禁用网络的情况
        manager.configure_network("test-vm").await.unwrap();
        manager.cleanup_network("test-vm").await.unwrap();
    }
    
    #[tokio::test]
    async fn test_network_isolation() {
        let config = NetworkConfig::default();
        let manager = NetworkManager::new(config);
        
        // 由于网络命名空间需要root权限，这里只测试接口是否正确
        // 在真实环境中会创建网络隔离
        let result = manager.create_network_isolation("test-vm").await;
        // 在测试环境中可能失败，但不影响接口验证
        match result {
            Ok(_) => println!("Network isolation created successfully"),
            Err(e) => println!("Network isolation failed (expected in test env): {}", e),
        }
    }
}